using System;
using System.Collections.Generic;
using Framework.Utils;
using UnityEngine;

namespace Framework.Save
{
    public class SaveControl<SaveType> where SaveType : Enum
    {

        public SaveConfig Config { get; private set; }

        private Dictionary<SaveType, Dictionary<string, byte[]>> _bytesCaches;

        public SaveControl()
        {
            this._bytesCaches = new Dictionary<SaveType, Dictionary<string, byte[]>>();
            this.Config       = SaveConfig.CreateConfig();
        }

        public void SetConfig(SaveConfig saveConfig)
        {
            this._bytesCaches.Clear();
            this.Config = saveConfig;
        }

        #region 基础数据操作 ---------------------------------------------------------------

        /// <summary>
        /// 是否有指定存档
        /// </summary>
        /// <param name="saveGroup"></param>
        /// <returns></returns>
        public bool HasSave(SaveType saveGroup, string table = "") { return FileHelper.CheckPath(this.Config.RootPath + "/" + saveGroup + table); }


        /// <summary>
        /// 删除指定存档文件
        /// </summary>
        /// <param name="saveGroup"></param>
        /// <param name="table"></param>
        public void DeleteSave(SaveType saveGroup, string table = "")
        {
            FileHelper.DeleteFile(this.Config.RootPath, saveGroup + table);
            this.ClearCache(saveGroup, table);
        }

        /// <summary>
        /// 数据存档
        /// </summary>
        /// <param name="saveGroup"></param>
        /// <param name="value"></param>
        public void Save(SaveType saveGroup, object value, string table = "")
        {
            //序列化数据
            var bytes = this.Config._saveSerializer.Serialize(value);
            if (this._bytesCaches.ContainsKey(saveGroup) && this._bytesCaches[saveGroup].ContainsKey(table))
                this._bytesCaches[saveGroup][table] = bytes;
            this.Config._saveHandler.WriteData(this.Config.RootPath, saveGroup + table, bytes);
        }

        /// <summary>
        /// 数据加载
        /// </summary>
        /// <param name="saveGroup"></param>
        public T Load<T>(SaveType saveGroup, string table = "")
        {
            try
            {
                var bytes = this.Config._saveHandler.ReadData(this.Config.RootPath, saveGroup + table);
                if (bytes != null)
                {
                    return this.Config._saveSerializer.Deserialize<T>(bytes);
                }
            }
            catch (Exception e)
            {
                Debug.LogError("存档损坏" + e);
            }
            return default;
        }

        #endregion


        /// <summary>
        /// 快速存储，只会将数据序列化到缓存中(内存)，需要手动调用Flush方法将数据写入到磁盘
        /// </summary>
        /// <param name="saveGroup"></param>
        /// <param name="value"></param>
        /// <param name="table"></param>
        public void QuickSave(SaveType saveGroup, object value, string table = "")
        {
            if (value == null)
            {
                return;
            }

            if (!this._bytesCaches.ContainsKey(saveGroup))
            {
                this._bytesCaches[saveGroup] = new Dictionary<string, byte[]>();
            }

            var bytes = this.Config._saveSerializer.Serialize(value);
            this._bytesCaches[saveGroup][table] = bytes;
        }

        /// <summary>
        /// 快速加载，将会优先从缓存读取数据，如果缓存区没有数据则尝试从磁盘中读取指定数据并缓存
        /// </summary>
        /// <param name="saveGroup"></param>
        /// <param name="table"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T QuickLoad<T>(SaveType saveGroup, string table = "")
        {
            byte[] obytes = null;
            if (!this._bytesCaches.ContainsKey(saveGroup) || !this._bytesCaches[saveGroup].ContainsKey(table))
            {
                this._bytesCaches[saveGroup]        = new Dictionary<string, byte[]>();
                obytes                              = this.Config._saveHandler.ReadData(this.Config.RootPath, saveGroup + table);
                this._bytesCaches[saveGroup][table] = obytes;
            }
            else
            {
                obytes = this._bytesCaches[saveGroup][table];
            }

            byte[] bytes = new byte[obytes.Length];
            obytes.CopyTo(bytes, 0);
            if (bytes != null)
            {
                return this.Config._saveSerializer.Deserialize<T>(bytes);
            }

            return default;
        }

        /// <summary>
        /// 将指定缓存写入到磁盘
        /// </summary>
        /// <param name="saveType"></param>
        public void Flush(SaveType saveType)
        {
            if (this._bytesCaches.ContainsKey(saveType))
            {
                var keys = this._bytesCaches[saveType].Keys;
                foreach (var key in keys)
                {
                    this.Flush(saveType, key);
                }
            }
        }

        /// <summary>
        /// 将指定缓存内容写入到磁盘
        /// </summary>
        /// <param name="saveType"></param>
        /// <param name="table"></param>
        public void Flush(SaveType saveType, string table)
        {
            if (this._bytesCaches.ContainsKey(saveType) && this._bytesCaches[saveType].ContainsKey(table))
            {
                Debug.Log("写入数据： " + saveType + table);
                this.Config._saveHandler.WriteData(this.Config.RootPath, saveType + table, this._bytesCaches[saveType][table]);
            }
        }

        /// <summary>
        /// 将缓存区所有数据写入到磁盘
        /// </summary>
        public void FlushAll()
        {
            foreach (var cachesKey in this._bytesCaches.Keys)
            {
                this.Flush(cachesKey);
            }
        }

        public void ClearCache(SaveType saveType) { this._bytesCaches.Remove(saveType); }

        public void ClearCache(SaveType saveType, string table)
        {
            if (this._bytesCaches.ContainsKey(saveType))
            {
                this._bytesCaches[saveType].Remove(table);
            }
        }

        public void ClearCacheAll() { this._bytesCaches.Clear(); }

    }
}